module mculib.baremetal.common;



import std.traits:isUnsigned,isNumeric,isScalarType;
import std.meta:allSatisfy;
import std.typecons:isBitFlagEnum;

 
/**
* 组合位或操作
* Params: 
*     T = 位域类型
*     a = 位域值1
*/
template combineOr(T...)
if (allSatisfy!(isScalarType, typeof(T)) )    /// 所有元素都是uint类型
{
	static if(T.length >= 2){
		enum combineOr = (T[0] ) | combineOr!(T[1..$]);
	}else static if(T.length == 1){
		enum combineOr = (T[0] );
	}else{
		enum combineOr = 0;
	}
}

unittest
{
    assert(combineOr!() == 0);
    assert(combineOr!(0) == 0);
    assert(combineOr!(1) == 1);
    assert(combineOr!(0,1) == 1);
    assert(combineOr!(1,0) == 1);
    assert(combineOr!(0,1,0) == 1);
    assert(combineOr!(1,0,1) == 1);
    assert(combineOr!(0,1,1) == 1);
    assert(combineOr!(1,1,0) == 1);
}



/**
    建立位域掩码
    Params: 
        T = 位域类型
        offset = 起始偏移位置
        width = 位域宽度
    Returns: 位域掩码
    Example:
        uint mask = MakeBitField!(uint)(0, 1); // 0b0001

*/
static T makeBitField(T = uint)(size_t offset, size_t width)
if(isUnsigned!T)
{
    return (T.max >>> (T.sizeof * 8 - width)) << offset;
}

unittest
{
    assert(makeBitField!(uint)(0, 1) == 0b0001);
    assert(makeBitField!(uint)(1, 2) == 0b0110);
    assert(makeBitField!(uint)(2, 3) == 0b0001_1100);
}

template isUint(T)
{
    enum bool isUint = is(T == uint);
}

template isEnum(E)
{
    static if(is(E == enum)){
        enum bool isEnum = true;
    }else{
        enum bool isEnum = false; 
    }
}

/**
    按位游标组合出位域掩码
    Params: 
        T = 位域列表
*/
template combineMasks(T...) 
if (allSatisfy!(isUint, typeof(T)) )    /// 所有元素都是uint类型
{
	static if(T.length >= 2){
		enum combineMasks = (1u << T[0] ) | combineMasks!(T[1..$]);
	}else static if(T.length == 1){
		enum combineMasks = (1u << T[0] );
	}else{
		enum combineMasks = 0;
	}
}

template combineMasks( T... ) 
if(allSatisfy!(isEnum, typeof(T)))    /// 所有元素都是enum类型
{
    static if(T.length >= 2){
        enum combineMasks = (combineMasks!(T[1..$]) | T[0]);
    }else static if(T.length == 1){
        enum combineMasks = (T[0]);
    }else{
        enum combineMasks = 0;
    }
}

unittest
{
    assert(combineMasks!() == 0);
    assert(combineMasks!(0) == 1);
    assert(combineMasks!(1) == 2);
    assert(combineMasks!(2) == 4);
    assert(combineMasks!(3) == 8);
    assert(combineMasks!(0,1,2,3) == 0x0f);
}

/**
    转换到小写字母
    Params: 
        str = 字符串类型
    ---
    ToLower!("Hello World") == "hello world"
    ---
*/
template ToLower(string v)
{
    import std.ascii : toLower;
    static if(v.length == 0){
        enum ToLower = "";
    }else{
        enum ToLower = ToLower!(v[0..v.length-1]) ~ v[v.length-1].toLower;
    }
}

unittest
{
    assert(ToLower!"Hello World" == "hello world");
    assert(ToLower!"12345" == "12345");
    assert(ToLower!"ABCDEF" == "abcdef");
}

/**
    转换到大写字母
    Params: 
        str = 字符串类型
*/
template ToUpper(string v)
{
    import std.ascii : toUpper;
    import std.complex;
    static if(v.length == 0){
        enum ToUpper = "";
    }else{
        enum ToUpper = ToUpper!(v[0..v.length-1]) ~ v[v.length-1].toUpper;
    }
}

unittest
{
    assert(ToUpper!"Hello World" == "HELLO WORLD");
    assert(ToUpper!"12345" == "12345");
    assert(ToUpper!"ABCDEF" == "ABCDEF");
}

/**
    忽略大小写比较字符串
    Params: 
        str1 = 字符串类型1
        str2 = 字符串类型2
*/
template IgnoreCaseCompare(string str1, string str2)
{
    static if(str1.length != str2.length){
        enum IgnoreCaseCompare = false;
    }else{
        enum IgnoreCaseCompare = (ToLower!str1 == ToLower!str2);
    };
}

unittest
{   
    assert(IgnoreCaseCompare!("Hello World","hello world") == true);
    assert(IgnoreCaseCompare!("12345","12345") == true);
    assert(IgnoreCaseCompare!("ABCDEF","abcdef") == true);
}

/**
	统计位域宽度
	Params:
		value = 位域值
	Return:
		位域宽度
*/
static size_t bitFieldWidth(T)(T value)
if(isUnsigned!T)
{
	size_t width = 0;
	for(;value!= 0;value>>>=1)
	{
		if((value & 1) || (width !=0)) width++;
	}
	return width;
}

unittest
{
	assert(bitFieldWidth(0b0001) == 1);
	assert(bitFieldWidth(0b0110) == 2);
	assert(bitFieldWidth(0b0001_1100) == 3);
}

/**
	统计位域中第一个`置位`的位置
	
	Params:
		value = 位域值
	Return:
		位域右侧第一个`置位`的位置
*/
/*
static size_t bitFieldFirst(T)(T value)
if(isUnsigned!T)
{
	size_t pos = 0;
	for(;value!= 0;value>>>=1)
	{
		if(value & 1) return pos;
		pos++;
	}
	return pos;
}

unittest
{
	assert(bitFieldFirst(0b0001) == 0);
	assert(bitFieldFirst(0b0110) == 1);
	assert(bitFieldFirst(0b0001_1100) == 2);
}
*/
/**
	统计位域中最后一个`置位`的位置
	
	Params:
		value = 位域值
	Return:
		位域左侧第一个`置位`的位置
*/
/*
static size_t bitFieldLast(T)(T value)
if(isUnsigned!T)
{
	size_t pos = 0;
	if(value!=0){
		auto start = bitFieldFirst(value);
		auto width = bitFieldWidth(value);
		pos = start + width - 1;
	}
	return pos;
}

unittest
{
	assert(bitFieldLast(0b0001) == 0);
	assert(bitFieldLast(0b0110) == 1);
	assert(bitFieldLast(0b0001_1100) == 2);
}
*/
/**
	设置位域值
	Params:
		value = 位域值
		offset = 起始偏移位置
		width = 位域宽度
		newValue = 新的位域值
	Return:
		设置后的位域值
*/
/*
static T setBitField(T)(T value, size_t offset, size_t width, T newValue)
if(isUnsigned!T)
{
	auto mask = makeBitField!(T)(offset, width);
	auto oldValue = (value & mask) >> offset;
	auto newMask = makeBitField!(T)(offset, width) ^ oldValue;
	return (value & ~mask) | (newValue << offset & newMask);
}

unittest
{
	assert(setBitField(0b0001, 0, 1, 1) == 0b0001);
	assert(setBitField(0b0001, 0, 1, 0) == 0b0000);
	assert(setBitField(0b0110, 1, 2, 0b11) == 0b0111);
	assert(setBitField(0b0001_1100, 2, 3, 0b111) == 0b0011_1111);
}
*/

/**
* 内存映射地址,返回一个内存指针,用于访问外设
* 不做任何地址检查
* Examples:
* ---
* enum RegMap = mappedAddress!(ushort,0x4002_1000);
* ---
*/
/*
template mappedAddress(T,size_t paddr)
{
    enum T* mappedAddress = cast(T*)paddr;
}
*/


/**
* 空函数模板,用于占位
*/
T emptyFunc(T,Args...)(Args args) => T.init;


/**
* 通过size返回可用的类型
*/
/*
template getAvailableType(size_t size)
{
    static if(size == 1)
        alias getAvailableType = bool;
    else static if(size <= 8)
        alias getAvailableType = byte; 
    else static if(size <= 16)
        alias getAvailableType = short;
    else static if(size <= 32)
        alias getAvailableType = int;
    else
        static assert(false," size > 32");
}

*/